package com.wm.blog_gateway.service;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wm.blog_common.base.BeanUtils;
import com.wm.blog_common.bean.PageHelper;
import com.wm.blog_common.bean.QueryPage;
import com.wm.blog_common.constatnt.ErrorConstant;
import com.wm.blog_common.domain.TRouteDO;
import com.wm.blog_common.entity.TRoute;
import com.wm.blog_common.result.Result;
import com.wm.blog_gateway.dao.TRouteDAO;
import com.wm.blog_gateway.query.TRouteQuery;
import com.wm.blog_gateway.vo.RouteFilterVo;
import com.wm.blog_gateway.vo.RoutePredicateVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wm_yu
 * @since 2020-03-27
 */
@Service
@Slf4j
public class TRouteService{
    @Autowired
    private TRouteDAO tRouteDAO;

    /**
     * 动态路由服务
     */
    @Autowired
    private DynamicRouteService dynamicRouteService;

    /**
     * 根据ID查询
     * @param id
     * @return
     */
    public Result<TRouteDO> selectById(Long id){
        return Result.success(BeanUtils.copyProperties(tRouteDAO.getById(id),TRouteDO.class));
    }

    /**
    * 根据ID删除
    * @param id
    * @return
    */
    public Result deleteById(Long id){
        if(ObjectUtils.isEmpty(id)){
            return Result.failure(ErrorConstant.ROUTE_ID_EMPTY);
        }
        //查询route_id
        TRoute route = Optional
                .ofNullable(tRouteDAO.getById(id))
                .orElse(new TRoute());
        if(ObjectUtils.isEmpty(route.getId())){
            return Result.failure(ErrorConstant.ROUTE_NOT_EXSIT);
        }
        if(tRouteDAO.removeById(id)){
            //删除动态路由
            Mono<ResponseEntity<Object>> mono = dynamicRouteService.delete(route.getRouteId());
            return Result.success(mono);
        }
        return Result.failure(ErrorConstant.ROUTE_DELETE_FAIL);
    }

    /**
    * 添加
    * @param route
    * @return
    */
    public Result insert(TRoute route){
        route = Optional.ofNullable(route).orElse(new TRoute());
        if(StringUtils.isEmpty(route.getRouteId())){
            return Result.failure(ErrorConstant.ROUTE_ID_EMPTY);
        }
        //校验路由是否已经存在
        TRouteQuery query = new TRouteQuery();
        query.setRouteId(route.getRouteId());
        query.setLastSql(" limit 1");
        QueryWrapper<TRoute> wrapper = this.combineQuery(query);
        TRoute tRoute = Optional
                .ofNullable(tRouteDAO.getOne(wrapper))
                .orElse(new TRoute());
        if(!ObjectUtils.isEmpty(tRoute.getId())){
            return Result.failure(ErrorConstant.ROUTE_ALEXSIT);
        }
        //新增路由信息
       if(tRouteDAO.save(route)){
           //执行动态路由添加
           dynamicRouteService.add(this.routeDefinition(route));
           return Result.success();
       }
        return Result.failure(ErrorConstant.ROUTE_ADD_FAIL);
    }

    /**
    * 修改路由信息
    * @return
    */
    public Result update(TRoute route){
        route = Optional.ofNullable(route).orElse(new TRoute());
        if(StringUtils.isEmpty(route.getRouteId())){
            return Result.failure(ErrorConstant.ROUTE_ID_EMPTY);
        }
        if(tRouteDAO.updateById(route)){
            //修改动态路由
            dynamicRouteService.update(this.routeDefinition(route));
            return Result.success();
        }
        return Result.failure(ErrorConstant.ROUTE_EDIT_FAIL);
    }

    /**
    * 统计总数
    *
    * @param query
    * @return
    */
    public Result<Integer> count(TRouteQuery query) {
        return Result.success(tRouteDAO.count(this.combineQuery(query)));
    }

    /**
    * 列表查询
    * @param query
    * @return
    */
    public Result<List<TRouteDO>> list(TRouteQuery query){
        return Result.success(BeanUtils.copyListProperties(tRouteDAO.list(this.combineQuery(query)),TRouteDO.class));
    }
    /**
    * 分页查询
    * @param page
    * @return
    */
    public Result<Page<TRouteDO>> page(QueryPage page, TRouteQuery query){
        return Result.success(PageHelper.newPage(tRouteDAO.page(page,this.combineQuery(query)),TRouteDO.class));
    }


    /**
     * 刷新路由
     * @return
     */
    public Result refresh() {
        //查询数据库中所有的路由信息
        List<TRoute> routeList = Optional
                .ofNullable(tRouteDAO.list())
                .orElse(Collections.emptyList());
        routeList.forEach(x -> {
            //更新路由
            dynamicRouteService.update(this.routeDefinition(x));
        });
        return Result.success();
    }




    /**
    * 组装查询条件
    *
    * @param query
    * @return
    */
    private QueryWrapper<TRoute> combineQuery(TRouteQuery query) {
        QueryWrapper<TRoute> wrapper = new QueryWrapper<>();
        Optional.ofNullable(query).ifPresent(x -> {
            Optional.ofNullable(query.getRouteId()).filter(org.apache.commons.lang3.StringUtils::isNotEmpty).ifPresent(y -> {
                wrapper.eq("route_id",y);
            });
            Optional.ofNullable(query.getLastSql()).filter(org.apache.commons.lang3.StringUtils::isNotEmpty).ifPresent(wrapper::last);
        });
        return wrapper;
    }











    /**
     * 初始化RouteDefinition 组装动态路由信息
     *
     * @param route route
     * @return RouteDefinition
     */
    private RouteDefinition routeDefinition(TRoute route) {
        RouteDefinition routeDefinition = new RouteDefinition();
        // id
        routeDefinition.setId(route.getRouteId());
        // predicates
        if (!StringUtils.isEmpty(route.getPredicates())){
            routeDefinition.setPredicates(predicateDefinitions(route));
        }
        // filters
        if (!StringUtils.isEmpty(route.getFilters())) {
            routeDefinition.setFilters(filterDefinitions(route));
        }
        // uri
        routeDefinition.setUri(URI.create(route.getUri()));
        return routeDefinition;
    }

    /**
     * route中的断言字符串解析为数组,组装gateway动态路由
     * @param route route
     * @return List
     */
    private List<PredicateDefinition> predicateDefinitions(TRoute route) {
        List<PredicateDefinition> predicateDefinitions = new ArrayList<>();
        try {
            List<RoutePredicateVo> routePredicateVoList = new ArrayList<>();

            if(!StringUtils.isEmpty(route.getPredicates())){
                 routePredicateVoList = JSONObject.parseArray(route.getPredicates(), RoutePredicateVo.class);
            }
            if (CollectionUtils.isNotEmpty(routePredicateVoList)) {
                for (RoutePredicateVo routePredicateVo : routePredicateVoList) {
                    PredicateDefinition predicate = new PredicateDefinition();
                    predicate.setArgs(routePredicateVo.getArgs());
                    predicate.setName(routePredicateVo.getName());
                    predicateDefinitions.add(predicate);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return predicateDefinitions;
    }

    /**
     * route中的过滤器字符串解析为数组,组装gateway动态路由
     * @param route route
     * @return List
     */
    private List<FilterDefinition> filterDefinitions(TRoute route) {
        List<FilterDefinition> filterDefinitions = new ArrayList<>();
        try {
            List<RouteFilterVo> gatewayFilterDefinitions = new ArrayList<>();
            if(!StringUtils.isEmpty(route.getFilters())){
                gatewayFilterDefinitions.addAll(JSONObject.parseArray(route.getFilters(),RouteFilterVo.class));
            }

            if (CollectionUtils.isNotEmpty(gatewayFilterDefinitions)) {
                for (RouteFilterVo gatewayFilterDefinition : gatewayFilterDefinitions) {
                    FilterDefinition filterDefinition = new FilterDefinition();
                    filterDefinition.setName(gatewayFilterDefinition.getName());
                    filterDefinition.setArgs(gatewayFilterDefinition.getArgs());
                    filterDefinitions.add(filterDefinition);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return filterDefinitions;
    }



}







